<?php
/**
 * CK框架 模型类
 * @author wujibing<283109896@qq.com>
 * @version   3.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
class module extends ckEventObejct
{
    /**
     * 插入数据前事件
     * @var string
     */
    const EVENT_BEGIN_ADD_DATA = 'BEGIN_ADD_DATA';
    /**
     * 插入数据后事件
     * @var string
     */
    const EVENT_END_ADD_DATA = 'END_ADD_DATA';
    
    /**
     * 更新数据前事件
     * @var string
     */
    const EVENT_BEGIN_UPDATE_DATA = 'BEGIN_UPDATE_DATA';
    /**
     * 更新数据后事件
     * @var string
     */
    const EVENT_END_UPDATE_DATA = 'END_UPDATE_DATA';
    
    /**
     * 删除数据前事件
     * @var string
     */
    const EVENT_BEGIN_DELETE_DATA = 'BEGIN_DELETE_DATA';
    /**
     * 删除数据后事件
     * @var string
     */
    const EVENT_END_DELETE_DATA = 'END_DELETE_DATA';
    
	/**
	 * 模块对应的表名
	 * @var string
	 */
	protected $_tableName = '';

	/**
	 * 当前正在WHERE的字段
	 * @var string
	 */
	protected $_whereField = '';

	/**
	 * 数据表对应的字段
	 * @var array
	 */
	protected $_fields = array();

	/**
	 * 查询的数组信息
	 * @var array
	 */
	protected $_queryArr = array('where' => array(), 'tableName' => '', 
	'queryField' => '', 'order' => array(), 'limit' => array(), 'group' => array(), 
	'join' => array(), 'data' => array());

	/**
	 * 默认的DB链接
	 * @var int
	 */
	protected $_defaultConfigDb = 0;

	/**
	 * 主键
	 * @var string
	 */
	protected $_primary;

	/**
	 * 自动补全键
	 * @var array
	 */
	protected $_auto;

	/**
	 * 过滤属性
	 * @var array
	 */
	protected $_filter = array();

	/**
	 * 查询的值
	 * @var array
	 */
	protected $_data = array();
	
	/**
	 * 表名前缀
	 * @var string
	 */
	protected $_prefixTableName = '';
	/**
	 * db代理对象
	 * @var dbProxy2
	 */
	protected $_dbProxy ;
	protected $_addData = array();
	protected $_updateData = array();
	public function __construct ($moduleName = '')
	{
		if ($moduleName)
		{
			$this->_tableName = $moduleName;
		}
		if (!$this->_tableName)
		{
			throw new notTableName_module_Exception();
		}
		//link database
		$this->_dbProxy = new dbProxy2($this, $this->_defaultConfigDb);
		//获取表的字段类型
		if(!$this->_fields)
		{
			$this->getFields();
		}
		//设置默认事件
		$this->attach(self::EVENT_BEGIN_ADD_DATA, array($this,'beforAddFunc'));
		$this->attach(self::EVENT_END_ADD_DATA, array($this,'endAddFunc'));
		$this->attach(self::EVENT_BEGIN_UPDATE_DATA, array($this,'beforUpdateFunc'));
		$this->attach(self::EVENT_END_UPDATE_DATA, array($this,'endUpdateFunc'));
		$this->attach(self::EVENT_BEGIN_DELETE_DATA, array($this,'beforDeleteFunc'));
		$this->attach(self::EVENT_END_DELETE_DATA, array($this,'endDeleteFunc'));
	}
    /**
     * 设置表的前缀名
     * @param string $prefixName
     */
	public function setPrefixTableName($prefixName)
	{
	    $this->_prefixTableName = $prefixName;
	    $this->_queryArr['tableName'] = $this->_prefixTableName.$this->_tableName;
	}
	public function __get ($name)
	{
		return $this->_data[$name];
	}

	public function __set ($name, $value)
	{
		return isset($this->_fields[$name]) ? $this->_data[$name] = $value : '';
	}

	/**
	 * 返回查询数组
	 * @return array:
	 */
	public function getQueryArr ()
	{
		return $this->_queryArr;
	}

	/**
	 * 查询
	 * @return array
	 */
	public function query ($key='')
	{
		$result = $this->_dbProxy->query($key);
		$this->getLinkMethod('getData',array(&$result));
		$this->clearQuery();
		return $result;
	}
	/**
	 * 获取查询数量
	 */
	public function count ()
	{
		return (int)$this->_dbProxy->count();
	}
	/**
	 * 刪除 find的緩存
	 * @param string $value
	 */
	public function cleanFindCache($value)
	{
		cache::init('FILE');
		cache::del( $this->_tableName.'keyCache'.$value);
	}
	/**
	 * 根据主键查询
	 * @param mixed $value
	 * @param int $cacheTime
	 * 缓存时间 默认为0 不缓存
	 * @return boolean
	 */
	public function find ($value,$cacheTime = 0)
	{
		$key = '';
		if($cacheTime)
		{
			cache::init('FILE');
			$key = $this->_tableName.'keyCache'.$value;
			$data = cache::get($key);
			if($data)
			{
				$this->_data = $data;
				return true;
			}
		}
		$this->_data = $this->where($this->_primary)->equal($value)->getOne();
		if (! $this->_data)
		{
			return false;
		}
		if($cacheTime)
		{
			cache::set($key, $this->_data,$cacheTime);
		}
		return true;
	}

	/**
	 * 只获取一条查询
	 * @return array
	 */
	public function getOne ()
	{
		$result = $this->limit(0, 1)->query();
		if ($result)
		{
			return $result[0];
		}
		return array();
	}

	/**
	 * 查询字段
	 * @param mixed $fieldNames
	 * @return module
	 */
	public function queryField ($fieldNames)
	{
		if (is_array($fieldNames) && $fieldNames)
		{
			$this->_queryArr['queryField'] = $fieldNames;
		} else
		{
			$this->_queryArr['queryField'][] = $fieldNames;
		}
		return $this;
	}

	/**
	 * 增加数据
	 * @param array $data
	 * 插入的数组
	 * @param bool $isReplace
	 * 是否使用replace
	 */
	public function add($data,$isReplace = false)
	{
	    $this->checkData($data);
		$this->_addData = $this->filterData($data);
		$this->run(self::EVENT_BEGIN_ADD_DATA);
		$this->_queryArr['data'] = $this->_addData;
		$this->_queryArr['isReplace'] = $isReplace;
		$this->_dbProxy->insert();
		$this->run(self::EVENT_END_ADD_DATA);
		$this->clearQuery();
	}

	/**
	 * 更改数据
	 * @param array $data
	 * @param array $math 相关的数学
	 */
	public function update ($data = array(),$math = array())
	{
		if (!is_array($data) || ! $data)
		{
			$data = $this->_data;
		}
		$this->checkData($data);
		$this->_updateData = $this->filterData($data);
		$this->run(self::EVENT_BEGIN_UPDATE_DATA);
		$this->_queryArr['data'] = $this->_updateData;
		if($this->_data[$this->_primary] && ! $this->_queryArr['where'])
		{
		    $this->where($this->_primary)->equal($this->_data[$this->_primary]);
		}
		$this->_queryArr['math'] = $math;
		$this->_dbProxy->update();
		$this->run(self::EVENT_END_UPDATE_DATA);
		$this->clearQuery();
	}
	/**
	 * 删除
	 * 没有WHERE信息的是很会寻找有没find值。
	 * 如果有FIND值则删除find的信息
	 * 否则删除全部
	 */
	public function delete()
	{
		$this->run(self::EVENT_BEGIN_DELETE_DATA);
		//判断有没where存在
		if(!$this->_queryArr['where'] && $this->_data)
		{
		    $this->where($this->_primary)->equal($this->_data[$this->_primary]);
		}
		$this->_dbProxy->delete();
		$this->run(self::EVENT_END_DELETE_DATA);
		$this->clearQuery();
	}
	/**
	 * 
	 * @param module $joinModule
	 * 链接模块
	 * @param string $joinFiled
	 * 本模块链接的字段
	 * @param string $joinCondition
	 * 链接比较条件符 为了方便可以使用 joinCondition类提供的常量
	 * @param string $joinModlueField
	 * 链接模块的字段
	 * @param int $joinType
	 * 链接类型 为了方便可以使用 joinType类提供的常量
	 * @return module
	 */
	public function join (module $joinModule, $joinFiled, $joinCondition, $joinModlueField, $joinType)
	{
		//判断字段
		$this->checkField($joinFiled);
		$joinModule->checkField($joinModlueField);
		//链接表
		$this->_queryArr['join'][] = array($joinModule, $joinFiled, 
		$joinCondition, $joinModlueField, $joinType);
		return $this;
	}

	/**
	 * 数据库GROUP操作
	 * @param string $fieldName
	 * @throws notFindField_module_Exception
	 * @return module
	 */
	public function group ($fieldName)
	{
		$this->checkField($fieldName);
		$this->_queryArr['group'] = $fieldName;
		return $this;
	}

	/**
	 * * 设置查询的排序
	 * @param string $fieldName
	 * @param string $orderBy
	 * 默认为desc 其余为asc
	 * @throws notFindField_module_Exception
	 * @return module
	 */
	public function order ($fieldName, $orderBy = 'desc')
	{
		$this->checkField($fieldName);
		$orderIndex = $orderBy == 'desc' ? 1 : 0;
		$this->_queryArr['order'] = array($fieldName, $orderIndex);
		return $this;
	}

	/**
	 * 设置查询的数量
	 * @param int $startLimit
	 * @param int $nums
	 * @return module
	 */
	public function limit ($startLimit, $nums)
	{
		$startLimit = (int) $startLimit;
		$nums = (int) $nums;
		if ($startLimit < 0)
		{
			$startLimit = 0;
		}
		if ($nums < 1)
		{
			throw new limitNumNotLteZero_module_Exception();
		}
		$this->_queryArr['limit'] = array($startLimit, $nums);
		return $this;
	}

	/**
	 * where操作
	 * @param string $fieldName
	 * @throws notFindFieldException
	 * @return module
	 */
	public function where ($fieldName)
	{
		$this->checkField($fieldName);
		$this->_whereField = $fieldName;
		return $this;
	}

	/**
	 * where后的等于操作
	 * @param string $value
	 * @return module
	 */
	public function equal ($value)
	{
		$this->_checkWhereValue($value, 'equal');
		return $this;
	}

	/**
	 * where后的大于操作
	 * @param string $value
	 * @return module
	 */
	public function gt ($value)
	{
		$this->_checkWhereValue($value, 'gt');
		return $this;
	}

	/**
	 * where后的大于等于操作
	 * @param string $value
	 * @return module
	 */
	public function gte ($value)
	{
		$this->_checkWhereValue($value, 'gte');
		return $this;
	}
	/**
	 * where后的between and 操作
	 * 组合成
	 * between $betweenValue and $andValue
	 * @param string $betweenValue
	 * @param string $andValue
	 * @return module
	 */
	public function betweenAnd($betweenValue,$andValue)
	{
		$this->_checkWhereValue(array($betweenValue,$andValue), 'betweenAnd');
		return $this;
	}

	/**
	 * where后的小于操作
	 * @param string $value
	 * @return module
	 */
	public function lt ($value)
	{
		$this->_checkWhereValue($value, 'lt');
		return $this;
	}

	/**
	 * where后的小于等于操作
	 * @param string $value
	 * @return module
	 */
	public function lte ($value)
	{
		$this->_checkWhereValue($value, 'lte');
		return $this;
	}

	/**
	 * where后的不等于操作
	 * @param string $value
	 * @return module
	 */
	public function ne ($value)
	{
		$this->_checkWhereValue($value, 'ne');
		return $this;
	}

	/**
	 * where后的in操作
	 * @param string $value
	 * @return module
	 */
	public function in ($value)
	{
		$this->_checkWhereValue($value, 'in');
		return $this;
	}

	/**
	 * where后的not in操作
	 * @param string $value
	 * @return module
	 */
	public function nin ($value)
	{
		$this->_checkWhereValue($value, 'nin');
		return $this;
	}

	/**
	 * where后的like操作
	 * @param string $value
	 * @return module
	 */
	public function like ($value)
	{
		$this->_checkWhereValue($value, 'like');
		return $this;
	}

	/**
	 * 判断是否有该字段
	 * @param string $fieldName
	 * @throws notFindField_module_Exception
	 */
	public function checkField ($fieldName)
	{
		if (!isset($this->_fields[$fieldName]))
		{
			throw new notFindField_module_Exception($fieldName);
		}
	}

	/**
	 * 获取data数据
	 * @return array
	 */
	public function getData ()
	{
		return $this->_data;
	}
	/**
	 * 获取主键
	 * @return string
	 */
	public function getPrimary()
	{
		return $this->_primary;
	}
	/**
	 * 开启事务
	 */
	public function beginTransaction()
	{
		$this->_dbProxy->beginTransaction();
	}
	/**
	 * 提交事务
	 */
	public function commit()
	{
		$this->_dbProxy->commit();
	}
	/**
	 * 回滚事务
	 */
	public function rollBack()
	{
		$this->_dbProxy->rollBack();
	}
	/**
	 * 返回link数组
	 */
	public function getLink()
	{
		return $this->_link;
	}
	/**
	 * 赋值Where
	 * @param string $value
	 * @param string $method
	 * @throws notWhereException
	 */
	protected function _checkWhereValue ($value, $method)
	{
		if (! $this->_whereField)
		{
			throw new notWhere_module_Exception();
		}
		$this->_queryArr['where'][] = array($this->_whereField, $value, $method);
		$this->_whereField = null;
	}

	/**
	 * 插入数据前的操作
	 * @param array $data
	 */
	protected function beforAddFunc ()
	{

	}

	/**
	 * 插入数据后操作
	 */
	protected function endAddFunc ()
	{

	}

	/**
	 * 更新数据前的操作
	 */
	protected function beforUpdateFunc ()
	{

	}

	/**
	 * 更新数据后的操作
	 */
	protected function endUpdateFunc ()
	{

	}

	/**
	 * 删除数据前的操作
	 */
	protected function beforDeleteFunc ()
	{

	}

	/**
	 * 删除数据后的操作
	 */
	protected function endDeleteFunc ()
	{

	}
    
	/**
	 * 校验插入或者更新的数据是否有
	 * @param array $data
	 * @throws Exception
	 */
	private function checkData($data)
	{
	    if (! is_array($data) || ! $data)
	    {
	        throw new Exception('没有数据进行过滤');
	    }
	}
	/**
	 * 过滤数据
	 * @param array $data
	 * @throws base_base_Exception
	 * @return array
	 */
	private function filterData ($data)
	{
		$tmp = array();
		foreach ($this->_fields as $key => $value)
		{
			if (isset($this->_filter[$key]))
			{
				$this->filterAction($key, $data[$key]);
			}
			if (isset($data[$key]))
			{
				$tmp[$key] = $data[$key];
			}
		}
		if (! $tmp)
		{
			throw new Exception('过滤数据后没有数据进行更新/插入', __LINE__);
		}
		return $tmp;
	}

	/**
	 * 过滤的方法
	 * @param string $key
	 * @param mixed $value
	 * @throws Exception
	 * @return 
	 */
	private function filterAction ($key, $value)
	{
		// arr 0 {0 filter 1回调 2正则表达式 } 1 {} 2  msg 3参数数组
		$arr = $this->_filter[$key];
		$return = false;
		switch ($arr[0])
		{
			case 1: //Call Back
				//print_r($arr[1][1]);
				//$return = call_user_method_array($arr[1][1], $arr[1][0], array($value, $arr[3]));
				$return = call_user_func_array(array($arr[1][0], $arr[1][1]), array($value, $arr[3]));
				break;
			case 2: //正则表达式 必须返回BOOL
				$return = preg_match('/' . $arr[1] . '/', $value);
				break;
			default:
				$return = isset($arr[3]) ? filter::$arr[1]($value, $arr[3]) : filter::$arr[1]($value);
		}
		if (! $return)
		{
			throw new Exception($arr[2], __LINE__);
		}
	}

	private function clearQuery ()
	{
		$this->_queryArr['where'] = $this->_queryArr['order'] = $this->_queryArr['join'] = $this->_queryArr['data'] = $this->_queryArr['limit'] = $this->_queryArr['math'] = array();
		$this->_queryArr['group'] = $this->_queryArr['queryField'] = null;
	}
	private function getLinkMethod($callBack,$args = array())
	{
		if(!$this->isLink || !$this->_link)
		{
			return null;
		}
		if($this->_moduleLink == null)
		{
			$this->_moduleLink = new moduleLink($this);
		}
		call_user_func_array(array($this->_moduleLink,$callBack), $args);
	}
	/**
	 * 获取字段信息
	 * @throws base_base_Exception
	 */
	private function getFields ()
	{
		$cacheFile = CK_APPLICATION_DATA_DIR . 'fileds/' . $this->_tableName . '.f.php';
		if (file_exists($cacheFile))
		{
			$cacheArr = require $cacheFile;
			$this->_auto = $cacheArr['auto'];
			$this->_fields = $cacheArr['field'];
			$this->_primary = $cacheArr['primary'];
		} else
		{
			try
			{
				$fields = $this->_dbProxy->getFields($this->_queryArr['tableName']);
			} catch (queryFaild_sql_Exception $e)
			{
				throw new base_Exception(lang::getLang('__NOT_FOUND_TABLE_INFO__',array($this->_queryArr['tableName'])));
			}
			if ($fields)
			{
				foreach ($fields as $fieldsKey => $fieldsValue)
				{
					$this->_fields[$fieldsKey] = 1;
					if ($fieldsValue['primary'] == 1 && ! $this->_primaryKey)
					{
						$this->_primary = $fieldsKey;
					} elseif ($fieldsValue['default'] != null)
					{
						$this->_auto[$fieldsKey] = $fieldsValue['default'];
					}
				}
				$cacheArr = array('field' => $this->_fields, 'primary' => $this->_primary, 'auto' => $this->_auto);
				file::write($cacheFile, $cacheArr);
			}
		}
	}
}

/**
 * JOIN类型类
 * @author wujibing<283109896@qq.com>
 * @version   3.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
final class joinType
{

	/**
	 * 左链接
	 * @var int
	 */
	const leftJoin = 'LEFT';

	/**
	 * 右链接
	 * @var int
	 */
	const rightJoin = 'RIGHT';

	/**
	 * 内链接
	 * @var int
	 */
	const innerJoni = 'INNER';
}


/**
 * JOIN比较类
 * @author wujibing<283109896@qq.com>
 * @version   3.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
final class joinCondition
{

	/**
	 * 等于
	 * @var unknown_type
	 */
	const equal = '=';

	/**
	 * 大于
	 * @var unknown_type
	 */
	const gt = '>';

	/**
	 * 大于等于
	 * @var unknown_type
	 */
	const gte = '>=';

	/**
	 * 小于
	 * @var unknown_type
	 */
	const lt = '<';

	/**
	 * 小于等于
	 * @var unknown_type
	 */
	const lte = '<=';

	/**
	 * 不等于
	 * @var unknown_type
	 */
	const ne = '!=';
}

/**
 * 没有表名的模块异常
 * @author wujibing<283109896@qq.com>
 * @version   3.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
class notTableName_module_Exception extends base_Exception
{
    public function __construct()
    {
        parent::__construct('模块没有表名');
    }
}

/**
 * 没有找到字段异常
 * @author wujibing<283109896@qq.com>
 * @version   3.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
class notFindField_module_Exception extends base_Exception
{
    public function __construct($fieldName)
    {
        parent::__construct('没有找到'.$fieldName.'字段');
    }
}

/**
 * 没有WHERE信息字段
 * @author wujibing<283109896@qq.com>
 * @version   3.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
class notWhere_module_Exception extends base_Exception
{
    public function __construct()
    {
        parent::__construct('没有WHERE信息字段哦');
    }
}

/**
 * 查询的数量不能小于1异常
 * @author wujibing<283109896@qq.com>
 * @version   3.0
 * @category   CkFrameWork
 * @package  CkFrameWork
 * @subpackage lib
 */
class limitNumNotLteZero_module_Exception extends base_Exception
{
    public function __construct()
    {
        parent::__construct('查询的数量不能小于1哦');
    }
}